home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / createmovie / start code / qtsound.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  12.6 KB  |  474 lines

  1. /*
  2.     File:        QTSound.c
  3.     
  4.     Contains:    Sound code for QuickTime CreateMovie sample
  5.     
  6.     Written by:    Scott Kuechle
  7.                 (based heavily on QuickTime sample code in Inside Macintosh: QuickTime)
  8.  
  9.     Copyright:    © 1998 by Apple Computer, Inc. All rights reserved
  10.     
  11.     Change History (most recent first)
  12.     
  13.         <2>        9/28/98        rtm        changes for Metrowerks compiler
  14.         <1>        6/26/98        srk        first file
  15.  
  16.  
  17. */
  18.  
  19. /************************************************************
  20. *                                                           *
  21. *    INCLUDE FILES                                          *
  22. *                                                           *
  23. *************************************************************/
  24.  
  25.  
  26. #if !defined(_MSC_VER) && _WIN32
  27.     #include <Win32Headers.mch>
  28.     #define TARGET_OS_WIN32            1
  29. #else
  30.     #include <ConditionalMacros.h>
  31. #endif
  32.  
  33. #if TARGET_OS_WIN32
  34.     #include <QTML.h>
  35.     #define    STRICT
  36.     #include <windows.h>
  37. #endif
  38.  
  39. #include <Resources.h>
  40. #include <FixMath.h>
  41. #include <Sound.h>
  42.  
  43. #include "CreateMovie.h"
  44. #include "QTSound.h"
  45.  
  46. /************************************************************
  47. *                                                           *
  48. *    TYPE DEFINITIONS                                       *
  49. *                                                           *
  50. *************************************************************/
  51.  
  52. typedef SndCommand *SndCmdPtr;
  53.  
  54. #if PRAGMA_STRUCT_ALIGN
  55.     #pragma options align=mac68k
  56. #elif PRAGMA_STRUCT_PACKPUSH
  57.     #pragma pack(push, 2)
  58. #elif PRAGMA_STRUCT_PACK
  59.     #pragma pack(2)
  60. #endif
  61.  
  62.     /* 'snd ' resource format 1 - see the Sound Manager chapter of Inside Macintosh: Sound
  63.         for the details */
  64.     typedef struct 
  65.     {
  66.         short format;
  67.         short numSynths;
  68.     } Snd1Header, *Snd1HdrPtr, **Snd1HdrHndl;
  69.  
  70.     /* 'snd ' resource format 2 - see the Sound Manager chapter of Inside Macintosh: Sound
  71.         for the details */
  72.  
  73.     typedef struct 
  74.     {
  75.         short format;
  76.         short refCount;
  77.     } Snd2Header, *Snd2HdrPtr, **Snd2HdrHndl;
  78.  
  79.  
  80. #if PRAGMA_STRUCT_ALIGN
  81.     #pragma options align=reset
  82. #elif PRAGMA_STRUCT_PACKPUSH
  83.     #pragma pack(pop)
  84. #elif PRAGMA_STRUCT_PACK
  85.     #pragma pack()
  86. #endif
  87.  
  88. /************************************************************
  89. *                                                           *
  90. *    FUNCTION PROTOTYPES                                    *
  91. *                                                           *
  92. *************************************************************/
  93.  
  94. static void QTSound_CreateSoundDescription (Handle sndHandle,
  95.                                             SoundDescriptionHandle sndDesc,
  96.                                             long *sndDataOffset,
  97.                                             long *numSamples,
  98.                                             long *sndDataSize );
  99. static long QTSound_GetSndHdrOffset (Handle sndHandle);
  100.  
  101. /************************************************************
  102. *                                                           *
  103. *    CONSTANTS                                              *
  104. *                                                           *
  105. *************************************************************/
  106.  
  107. #define    kOurSoundResourceID 128
  108.  
  109. #define    kSoundSampleDuration 1
  110. #define    kSyncSample 0
  111. #define    kTrackStart    0
  112. #define    kMediaStart    0
  113. /* 
  114. for the following constants, please consult the Macintosh
  115. Audio Compression and Expansion Toolkit
  116. */
  117. #define kMACEBeginningNumberOfBytes 6
  118. #define kMACE31MonoPacketSize 2
  119. #define kMACE31StereoPacketSize 4
  120. #define kMACE61MonoPacketSize 1
  121. #define kMACE61StereoPacketSize 2
  122.  
  123.  
  124. /************************************************************
  125. *                                                           *
  126. *    QTSound_CreateMySoundTrack()                           *
  127. *                                                           *
  128. *    Creates a QuickTime movie sound track & media data     *
  129. *                                                           *
  130. *************************************************************/
  131.  
  132.  
  133. void QTSound_CreateMySoundTrack (Movie theMovie)
  134. {
  135.  
  136. // Step 1.
  137. // Insert "TrackMediaVars.clp" here
  138.  
  139.     Handle sndHandle = nil;
  140.  
  141. // Step 2.
  142. // Insert "SoundDescriptionVar.clp" here
  143.  
  144.     long sndDataOffset;
  145.     long sndDataSize;
  146.     long numSamples;
  147.     OSErr err = noErr;
  148.  
  149. #if TARGET_OS_WIN32
  150.  
  151.     char path[MAX_PATH+1];
  152.     short resID;
  153.     FSSpec fsspec;
  154.  
  155.  
  156.         fsspec.vRefNum = 0;
  157.         fsspec.parID = 0;
  158.         GetModuleFileName( NULL, path, MAX_PATH+1);
  159.  
  160.         NativePathNameToFSSpec((char *)&path, &fsspec, 0);
  161.  
  162.             /* open our application resource file so we
  163.                 can access the Macintosh 'snd ' resource */ 
  164.         resID = FSpOpenResFile(&fsspec, fsRdPerm);
  165.         CheckError (ResError(), "FSpOpenResFile error" );
  166.  
  167. #endif
  168.  
  169.         // Get the sound
  170.         sndHandle = GetResource('snd ', kOurSoundResourceID);
  171.         CheckError (ResError(), "GetResource error" );
  172.         if (sndHandle == nil)
  173.         {
  174.             return;
  175.         }
  176.  
  177.         // Allocate memory for the sound description
  178.         sndDesc = (SoundDescriptionHandle) NewHandle(4);
  179.         CheckError (MemError(), "NewHandle error" );
  180.  
  181.         // Create the sound description that correctly describes the sound samples
  182.         // obtained from the 'snd ' resource.
  183.         QTSound_CreateSoundDescription(sndHandle, 
  184.                                        sndDesc, 
  185.                                        &sndDataOffset, 
  186.                                        &numSamples, 
  187.                                        &sndDataSize);
  188.  
  189.         // 1. Create the track
  190.         
  191. // Step 3.
  192. // Insert "NewMovieTrack.clp" here
  193.  
  194.         CheckError (GetMoviesError(), "NewMovieTrack error" );
  195.  
  196.         // 2. Create the media for the track
  197.  
  198. // Step 4.
  199. // Insert "NewTrackMedia.clp" here
  200.  
  201.         CheckError (GetMoviesError(), "NewTrackMedia error" );
  202.  
  203.         // 3. Establish a media-editing session
  204.         err = BeginMediaEdits(theMedia);
  205.         CheckError( err, "BeginMediaEdits error" );
  206.         
  207.         // 3a. Add Samples to the media
  208.  
  209. // Step 5.
  210. // Insert "AddMediaSample.clp" here
  211.  
  212.         CheckError( err, "AddMediaSample error" );
  213.  
  214.         // 3b. End media-editing session
  215.         err = EndMediaEdits(theMedia);
  216.         CheckError( err, "EndMediaEdits error" );
  217.  
  218.         // 4. Inserts a reference to a media segment into the track
  219.  
  220. // Step 6.
  221. // Insert "InsertMediaIntoTrack.clp" here
  222.  
  223.         CheckError( err, "InsertMediaIntoTrack error" );
  224.  
  225.         if (sndDesc != nil)
  226.         {
  227.             DisposeHandle( (Handle)sndDesc);
  228.         }
  229.  
  230. /************************************************************
  231. *                                                           *
  232. *    QTSound_CreateSoundDescription()                       *
  233. *                                                           *
  234. *    Creates a SoundDescription structure for a given sound *
  235. *    sample                                                 *
  236. *                                                           *
  237. *************************************************************/
  238.  
  239. static void QTSound_CreateSoundDescription (Handle sndHandle,
  240.                                             SoundDescriptionHandle sndDesc,
  241.                                             long *sndDataOffset,
  242.                                             long *numSamples,
  243.                                             long *sndDataSize )
  244. {
  245.     long sndHdrOffset = 0;
  246.     long sampleDataOffset;
  247.     SoundHeaderPtr sndHdrPtr = nil;
  248.     long numFrames;
  249.     long samplesPerFrame;
  250.     long bytesPerFrame;
  251.     SoundDescriptionPtr sndDescPtr;
  252.  
  253.         *sndDataOffset = 0;
  254.         *numSamples = 0;
  255.         *sndDataSize = 0;
  256.  
  257.         SetHandleSize( (Handle)sndDesc, sizeof(SoundDescription) );
  258.         CheckError(MemError(),"SetHandleSize error");
  259.         
  260.         sndHdrOffset = QTSound_GetSndHdrOffset (sndHandle);
  261.         if (sndHdrOffset == 0)
  262.         {
  263.             CheckError(-1, "QTSound_GetSndHdrOffset error");
  264.         }
  265.  
  266.         /* we can use pointers since we don't move memory */
  267.         sndHdrPtr = (SoundHeaderPtr) (*sndHandle + sndHdrOffset);
  268.         sndDescPtr = *sndDesc;
  269.  
  270.         sndDescPtr->descSize = sizeof (SoundDescription);
  271.         /* total size of sound description structure */
  272.         sndDescPtr->resvd1 = 0;
  273.         sndDescPtr->resvd2 = 0;
  274.         sndDescPtr->dataRefIndex = 1;
  275.         sndDescPtr->compressionID = 0;
  276.         sndDescPtr->packetSize = 0;
  277.         sndDescPtr->version = 0;
  278.         sndDescPtr->revlevel = 0;
  279.         sndDescPtr->vendor = 0; 
  280.  
  281.         switch (sndHdrPtr->encode) 
  282.         {
  283.             case stdSH:
  284.                 sndDescPtr->dataFormat = kRawCodecType;
  285.                 /* uncompressed offset-binary data */
  286.                 sndDescPtr->numChannels = 1;
  287.                 /* number of channels of sound */
  288.                 sndDescPtr->sampleSize = 8;
  289.                 /* number of bits per sample */
  290.                 sndDescPtr->sampleRate = sndHdrPtr->sampleRate;
  291.                 /* sample rate */
  292.                 *numSamples = sndHdrPtr->length;
  293.                 *sndDataSize = *numSamples;
  294.                 bytesPerFrame = 1; 
  295.                 samplesPerFrame = 1;
  296.                 sampleDataOffset = (Ptr)&sndHdrPtr->sampleArea - (Ptr)sndHdrPtr;
  297.             break;
  298.  
  299.             case extSH:
  300.             {
  301.                 ExtSoundHeaderPtr extSndHdrP;
  302.  
  303.                     extSndHdrP = (ExtSoundHeaderPtr)sndHdrPtr;
  304.                     sndDescPtr->dataFormat = kRawCodecType;
  305.                     /* uncompressed offset-binary data */
  306.  
  307.                     /* we typecast a long to a short here, and it should really be fixed */
  308.                     sndDescPtr->numChannels = (short)extSndHdrP->numChannels;
  309.                     /* number of channels of sound */
  310.                     sndDescPtr->sampleSize = extSndHdrP->sampleSize;
  311.                     /* number of bits per sample */
  312.                     sndDescPtr->sampleRate = extSndHdrP->sampleRate; 
  313.                     /* sample rate */
  314.                     numFrames = extSndHdrP->numFrames;
  315.                     *numSamples = numFrames;
  316.                     bytesPerFrame = extSndHdrP->numChannels * ( extSndHdrP->sampleSize / 8);
  317.                     samplesPerFrame = 1;
  318.                     *sndDataSize = numFrames * bytesPerFrame;
  319.                     sampleDataOffset = (Ptr)(&extSndHdrP->sampleArea) - (Ptr)extSndHdrP;
  320.             }
  321.             break;
  322.  
  323.             case cmpSH:
  324.             {
  325.                 CmpSoundHeaderPtr cmpSndHdrP;
  326.  
  327.                 cmpSndHdrP = (CmpSoundHeaderPtr)sndHdrPtr;
  328.                 /* we typecast a long to a short here, and it should really be fixed */
  329.  
  330.                 sndDescPtr->numChannels = (short)cmpSndHdrP->numChannels;
  331.                 /* number of channels of sound */
  332.                 sndDescPtr->sampleSize = cmpSndHdrP->sampleSize;
  333.                 /* number of bits per sample before compression */
  334.                 sndDescPtr->sampleRate = cmpSndHdrP->sampleRate;
  335.                 /* sample rate */
  336.                 numFrames = cmpSndHdrP->numFrames; 
  337.                 sampleDataOffset =(Ptr)(&cmpSndHdrP->sampleArea) - (Ptr)cmpSndHdrP;
  338.                 
  339.                 switch (cmpSndHdrP->compressionID) 
  340.                 {
  341.                     case threeToOne:
  342.                         sndDescPtr->dataFormat = kMACE3Compression;
  343.                         /* compressed 3:1 data */
  344.                         samplesPerFrame = kMACEBeginningNumberOfBytes; 
  345.                         *numSamples = numFrames * samplesPerFrame;
  346.                         
  347.                         switch (cmpSndHdrP->numChannels) 
  348.                         {
  349.                             case 1:
  350.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  351.                                                     * kMACE31MonoPacketSize;
  352.                             break;
  353.                             
  354.                             case 2:
  355.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  356.                                                     * kMACE31StereoPacketSize;
  357.                             break;
  358.                             
  359.                             default: 
  360.                                 CheckError(-1, "Corrupt sound data" );
  361.                             break;
  362.                         }
  363.                         
  364.                     *sndDataSize = numFrames * bytesPerFrame;
  365.                     break;
  366.                     
  367.                     case sixToOne:
  368.                         sndDescPtr->dataFormat = kMACE6Compression; 
  369.                         /* compressed 6:1 data */
  370.                         samplesPerFrame = kMACEBeginningNumberOfBytes; 
  371.                         *numSamples = numFrames * samplesPerFrame;
  372.                         
  373.                         switch (cmpSndHdrP->numChannels) 
  374.                         {
  375.                             case 1:
  376.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  377.                                                     * kMACE61MonoPacketSize; 
  378.                             break;
  379.                             
  380.                             case 2:
  381.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  382.                                                     * kMACE61StereoPacketSize; 
  383.                             break;
  384.                             
  385.                             default:
  386.                                 CheckError(-1, "Corrupt sound data" );
  387.                             break;
  388.                         }
  389.                         
  390.                         *sndDataSize = (*numSamples) * bytesPerFrame;
  391.                     break;
  392.                     
  393.                     default:
  394.                         CheckError(-1, "Corrupt sound data" );
  395.                     break;
  396.                     }
  397.                     
  398.                 } /* switch cmpSndHdrP->compressionID:*/
  399.                 
  400.                 break;  /* of cmpSH: */
  401.  
  402.                 default:
  403.                     CheckError(-1, "Corrupt sound data" );
  404.                 break;
  405.  
  406.         } /* switch sndHdrPtr->encode */
  407.         
  408.     *sndDataOffset = sndHdrOffset + sampleDataOffset; 
  409.  
  410.  
  411. /************************************************************
  412. *                                                           *
  413. *    QTSound_GetSndHdrOffset()                              *
  414. *                                                           *
  415. *    Returns an pointer to the first sound command in the   *
  416. *    sound resource                                         *
  417. *                                                           *
  418. *************************************************************/
  419.  
  420. static long QTSound_GetSndHdrOffset (Handle sndHandle)
  421. {
  422.     short howManyCmds;
  423.     long sndOffset = 0;
  424.     Ptr sndPtr;
  425.  
  426.         if (sndHandle == nil)
  427.         {
  428.             return 0;
  429.         }
  430.         sndPtr = *sndHandle;
  431.         if (sndPtr == nil)
  432.         {
  433.             return 0;
  434.         }
  435.  
  436.         if ((*(SndListPtr)sndPtr).format == firstSoundFormat) 
  437.         {
  438.             short synths = ((SndListPtr)sndPtr)->numModifiers;
  439.             sndPtr += ( sizeof(Snd1Header) + (sizeof(ModRef) * synths) );
  440.         }
  441.         else 
  442.         {
  443.             sndPtr += sizeof(Snd2Header);
  444.         }
  445.  
  446.         howManyCmds = *(short *)sndPtr;
  447.  
  448.         sndPtr += sizeof(howManyCmds);
  449.         /* 
  450.         sndPtr is now at the first sound command--cruise all
  451.         commands and find the first soundCmd or bufferCmd
  452.         */
  453.         while (howManyCmds > 0) 
  454.         {
  455.             switch (((SndCmdPtr)sndPtr)->cmd) 
  456.             {
  457.                 case (soundCmd + dataOffsetFlag):
  458.                 case (bufferCmd + dataOffsetFlag):
  459.                     sndOffset = ((SndCmdPtr)sndPtr)->param2;
  460.                     howManyCmds = 0;    /* done, get out of loop */
  461.                 break;
  462.                 
  463.                 default:/* catch any other type of commands */
  464.                     sndPtr += sizeof(SndCommand);
  465.                     howManyCmds--;
  466.                 break;
  467.             }
  468.         }/* done with all commands */
  469.  
  470.         return sndOffset;
  471. }/* of GetSndHdrOffset */ 
  472.